#include "server.h"
#include "iothread.h"

struct server s;

//客户端退出，添加需要close的fd
void addClosefd(server* s, int fd)
{
  s->close_fd_list_.push_front(fd);
}

//写操作，不是回调函数
void writeToClient(eventLoop* el)
{
  char buff[MAX_WRITEDBUFF] = { 0 };
  size_t writelen = el->writebuff_.ringBuffReadLen();
  buff[0] = 0;
  el->writebuff_.readBuff(buff, writelen);
  //std::cout << buff << std::endl;
  std::string response = 
  "HTTP/1.1 200 OK\r\n"
  "Content-Type: text/plain\r\n"
  "Content-Length: 12\r\n"
  "\r\n"
  ;
  response += buff;
  writelen = response.size();
  std::cout << "writeToClient...." << pthread_self() << std::endl;
  write(el->fd_, response.c_str(), writelen);
  //int num = write(el->fd_, response.c_str(), writelen);
  // while(num && (size_t)num < writelen)
  // {
  //   writelen -= num;
  //   num = write(el->fd_, buff + num, writelen);
  // }
}

//开启io-thread，使用iothread读写
int postponeClientRead(eventLoop* el)
{
  if(el && s.io_thread_active_ && !(el->flag_& CLIENT_PENDING_READ))
  {
    el->flag_ |= CLIENT_PENDING_READ;
    s.client_read_list_.push_back(el);
    return 1;
  }
  else 
    return 0;
}

void parseReadBuff(eventLoop* el)
{
  //直接发送给客户端
  char buff[MAX_READBUFF] = { 0 };
  size_t readlen = el->readbuff_.ringBuffReadLen();
  el->readbuff_.readBuff(buff, readlen);
  //std::cout << buff << std::endl;
  el->writebuff_.writeBuff(buff, readlen);
  //放入全局写操作队列
  s.client_write_list_.push_back(el);
}

void readQueryFromClient(eventLoop* el)
{
  if(el)
  {
    //成功使用io-thread进行读写
    if(postponeClientRead(el))
      return;

    int fd = el->fd_;
    char buff[MAX_READBUFF] = { 0 };
    int ret = read(fd, buff, MAX_READBUFF);
    if(ret < 0)
    {
      addClosefd(&s, fd);
      return;
    }
    else if(ret == 0)
    {
      addClosefd(&s, fd);
      return;
    }
    else 
    {
      std::cout << "readQueryFromClient..." << pthread_self() << std::endl;
      //写入el的缓冲区
      el->readbuff_.writeBuff(buff, (size_t)ret);
      parseReadBuff(el);
    }
  }
}

int setNonBlock(int fd, int non_block)
{
  int flags = 0;

  if((flags = fcntl(fd, F_GETFL)) < 0)
    return -1;

  if(non_block)
    flags |= O_NONBLOCK;

  if(!non_block)
    flags &= ~O_NONBLOCK;

  if(fcntl(fd, F_SETFL, flags) < 0)
    return -1;

  return -1;
}

void readHandler(reactor* rt, int fd)
{
  if(!rt)
    return;

  eventLoop* el = rt->getEventLoop(fd);
  if(el)
  {
    readQueryFromClient(el);
  }
}

void acceptHandler(reactor* rt, int fd)
{
  if(!rt)
    return;

    //std::cout << "acceptHandler..." << std::endl;
    int clientfd = 0;
  while(1)
  {
    struct sockaddr_in peer;
    socklen_t len = sizeof(peer);
    clientfd = accept(fd, (struct sockaddr*)&peer, &len); 
    if(clientfd == -1)
    {
      if(errno == EINTR)
        continue;
      else 
        return;
    }
    break;
  }
  //std::cout << "get a link..." << clientfd << std::endl;
  setNonBlock(clientfd, 1);
  rt->setReactorHandler(clientfd, readHandler, AE_READABLE);
}


void initServer(int port)
{
  s.sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
  if(s.sockfd_ < 0)
    exit(-1);
  s.port_ = port;
  int opt = 1;
  setsockopt(s.sockfd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

  struct sockaddr_in local;
  local.sin_family = AF_INET;
  local.sin_port = htons(s.port_);
  local.sin_addr.s_addr = htons(INADDR_ANY);
  if(bind(s.sockfd_,(struct sockaddr*)&local, sizeof(local)) < 0)
  {
    close(s.sockfd_);
    exit(-1);
  }

  if(listen(s.sockfd_, BACKLOG) < 0)
  {
    close(s.sockfd_);
    exit(-1);
  }
  //s.io_thread_active_ = 1;
  s.rt_ = new reactor; 

  setNonBlock(s.sockfd_, 1);
  s.rt_->setReactorHandler(s.sockfd_, acceptHandler, AE_READABLE);
  std::cout << "init server..." << std::endl;

  initThreadIOPool();
}

int waitEventOnce()
{
  handleClientReadUsingThread(); 

  handleClientWriteUsingThread();

  freeClients();
   
  int event_num = s.rt_->waitEpollEvent(); 
  int process = 0;
  for(int i = 0; i < event_num; ++i)
  {
    struct fireEvent* fe = s.rt_->getFireEvent(i);

    int mask = fe->mask_;
    int fd = fe->fd_;
    eventLoop* el = s.rt_->getEventLoop(fe->fd_);
    if(!el)
      continue;

    if(el->mask_ & AE_READABLE & mask)
      el->readHandler_(s.rt_, fd);

    if(el->mask_ & AE_WRITEABLE & mask)
      el->writeHandler_(s.rt_, fd);

    process++;
  }

  return process;
}

void waitEvent()
{
  while(!s.rt_->getStopState())
    waitEventOnce();
}


int main()
{
    initServer(9091);
    waitEvent();
    return 0;
}
